//
// Created by dwx on 2023/10/13.
//
#include "bsp_uart.h"
#include "string.h"
#include "stdio.h"
#include "stdarg.h"
#include "rtthread.h"


extern rt_sem_t Uart1Sem;   /* 信号量控制块 */
extern rt_sem_t Uart2Sem;   /* 信号量控制块 */

uint8_t uart1RecvData[255] = {0};    // 接收数据缓冲区
uint16_t uart1RecvLen = 0;           // 接收的数据长度

uint8_t uart2RecvData[255] = {0};    // 接收数据缓冲区
uint16_t uart2RecvLen = 0;           // 接收的数据长度

void USART3_Config(uint32_t MyBaudRate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = MyBaudRate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
    USART_Init(USART3, &USART_InitStructure);


    USART_Cmd(USART3, ENABLE);
}

////自定义串口2 的printf 函数
char UART3_TX_BUF[200];

void u3_printf(char *fmt, ...)    //无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表
{

    uint16_t i, j;
    va_list ap;          //va_list 是一个字符指针，可以理解为指向当前参数的一个指针，取参必须通过这个指针进行。
    rt_enter_critical();
    va_start(ap, fmt);   //va_start函数来获取参数列表中的参数，使用完毕后调用va_end()结束
    vsprintf((char *) UART3_TX_BUF, fmt, ap);    // 把生成的格式化的字符串存放在这里
    va_end(ap);
    i = strlen((const char *) UART3_TX_BUF);              //此次发送数据的长度
    for (j = 0; j < i; j++)                                                    //循环发送数据
    {
//        while((USART3->SR & 0X40) == 0);                    //循环发送,直到发送完毕
//        USART3->DR = UART3_TX_BUF[j];
        USART_SendData(USART3, UART3_TX_BUF[j]);
        while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
    }
    rt_exit_critical();
}


void USART1_Config(uint32_t MyBaudRate) {
    GPIO_InitTypeDef GPIO_InitStructure;                                       //  定义结构体
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    DMA_InitTypeDef DMA_InitStruct;            // DMA 配置

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  // 使能 DMA1 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        //  开启GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);     //  开启串口1时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                                   //   配置TXD
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                    //   复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                                         //   初始化PA9

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                                 //   配置RXD
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;        //    浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                                         //   初始化PA10

    USART_InitStructure.USART_BaudRate = MyBaudRate;                   //    配置串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;  //   8位数据位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                 //   1位停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;                       //   无校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    //  无硬件控制流
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                           //  配置RX | TX模式
    USART_Init(USART1, &USART_InitStructure);                                              //    初始化串口

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                       //     配置中断源
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;               //     抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                           //     响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                           //     使能中断通道
    NVIC_Init(&NVIC_InitStructure);                                                            //     初始化中断

    USART_ITConfig(USART1, USART_IT_IDLE,
                   ENABLE);  // 使能串口空闲中断，接收一帧数据产生 USART_IT_IDLE 空闲中断               //     使能串口接收中断
    USART_Cmd(USART1, ENABLE);

    /* 串口DMA配置 */

    DMA_DeInit(DMA1_Channel5);  // DMA1 通道5，寄存器复位

    // RX DMA1 通道5
    DMA_InitStruct.DMA_BufferSize = sizeof(uart1RecvData);      // 定义了接收的最大长度
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;             // 串口接收，方向是外设->内存
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;                   // 本次是外设到内存，所以关闭内存到内存
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) uart1RecvData;// 内存的基地址，要存储在哪里
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;// 内存数据宽度，按照字节存储
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;        // 内存递增，每次串口收到数据存在内存中，下次收到自动存储在内存的下一个位置
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;                  // 正常模式
    DMA_InitStruct.DMA_PeripheralBaseAddr = USART1_BASE + 0x04; // 外设的基地址，串口的数据寄存器
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;    // 外设的数据宽度，按照字节存储，与内存的数据宽度一致
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;   // 接收只有一个数据寄存器 RDR，所以外设地址不递增
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;            // 优先级
    DMA_Init(DMA1_Channel5, &DMA_InitStruct);

    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);// 使能DMA串口发送和接受请求
    DMA_Cmd(DMA1_Channel5, ENABLE);     // 使能接收

}


/* 清除DMA的传输数量寄存器 */
void uart1DmaClear(void) {
    DMA_Cmd(DMA1_Channel5, DISABLE);    // 关闭 DMA1_Channel5 通道
    DMA_SetCurrDataCounter(DMA1_Channel5, sizeof(uart1RecvData));   // 重新写入要传输的数据数量
    DMA_Cmd(DMA1_Channel5, ENABLE);     // 使能 DMA1_Channel5 通道
}


void USART1_IRQHandler(void)    // 串口1 的中断处理函数
{
    uint8_t clear;
    if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)   // 空闲中断
    {
        clear = USART1->SR; // 清除空闲中断
        clear = USART1->DR; // 清除空闲中断
        uart1RecvLen = sizeof(uart1RecvData) - DMA_GetCurrDataCounter(DMA1_Channel5);// 总的buf长度减去剩余buf长度，得到接收到数据的长度
        rt_sem_release(Uart1Sem);        /* 释放二值信号量 */
    }
}

void Uart1SendData(uint8_t *buff, uint16_t len) {
    rt_enter_critical();
    for (int i = 0; i < len; i++) {
        USART_SendData(USART1, buff[i]);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    }
    rt_exit_critical();
}


void USART2_Config(uint32_t MyBaudRate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    DMA_InitTypeDef DMA_InitStruct;            // DMA 配置


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  // 使能 DMA1 时钟


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = MyBaudRate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART2, &USART_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_ITConfig(USART2, USART_IT_IDLE,
                   ENABLE);  // 使能串口空闲中断，接收一帧数据产生 USART_IT_IDLE 空闲中断               //     使能串口接收中断
    USART_Cmd(USART2, ENABLE);


    /* 串口DMA配置 */

    DMA_DeInit(DMA1_Channel6);  // DMA1 通道5，寄存器复位

    // RX DMA1 通道5
    DMA_InitStruct.DMA_BufferSize = sizeof(uart2RecvData);      // 定义了接收的最大长度
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;             // 串口接收，方向是外设->内存
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;                   // 本次是外设到内存，所以关闭内存到内存
    DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) uart2RecvData;// 内存的基地址，要存储在哪里
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;// 内存数据宽度，按照字节存储
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;        // 内存递增，每次串口收到数据存在内存中，下次收到自动存储在内存的下一个位置
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;                  // 正常模式
    DMA_InitStruct.DMA_PeripheralBaseAddr = USART2_BASE + 0x04; // 外设的基地址，串口的数据寄存器
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;    // 外设的数据宽度，按照字节存储，与内存的数据宽度一致
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;   // 接收只有一个数据寄存器 RDR，所以外设地址不递增
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;            // 优先级
    DMA_Init(DMA1_Channel6, &DMA_InitStruct);

    USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);// 使能DMA串口发送和接受请求
    DMA_Cmd(DMA1_Channel6, ENABLE);     // 使能接收
}
void USART2_IRQHandler(void)    // 串口1 的中断处理函数
{
    uint8_t clear;
    if (USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)   // 空闲中断
    {
        clear = USART2->SR; // 清除空闲中断
        clear = USART2->DR; // 清除空闲中断
        uart2RecvLen = sizeof(uart2RecvData) - DMA_GetCurrDataCounter(DMA1_Channel6);// 总的buf长度减去剩余buf长度，得到接收到数据的长度
        rt_sem_release(Uart2Sem);        /* 释放二值信号量 */
    }
}

void uart2DmaClear(void) {
    DMA_Cmd(DMA1_Channel6, DISABLE);    // 关闭 DMA1_Channel5 通道
    DMA_SetCurrDataCounter(DMA1_Channel6, sizeof(uart2RecvData));   // 重新写入要传输的数据数量
    DMA_Cmd(DMA1_Channel6, ENABLE);     // 使能 DMA1_Channel5 通道
}


void Uart2SendData(uint8_t *buff, uint16_t len) {
    rt_enter_critical();
    for (int i = 0; i < len; i++) {
        USART_SendData(USART2, buff[i]);
        while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
    }
    rt_exit_critical();
}
